import pandas as pd
import numpy as np
from typing import Dict, Tuple, Optional
import warnings
warnings.filterwarnings('ignore')

class MarketStateAnalyzer:
    """
    市场状态分析器
    用于识别不同的市场环境，并为MACD评分系统提供动态权重调整
    """
    
    def __init__(self, data: pd.DataFrame):
        """
        初始化市场状态分析器
        
        Args:
            data: 包含OHLCV数据的DataFrame
        """
        self.data = data
        self.market_state = None
        self.volatility_regime = None
        self.trend_strength = None
        
    def analyze_market_state(self) -> Dict:
        """
        综合分析市场状态
        
        Returns:
            包含市场状态信息的字典
        """
        # 1. 趋势状态分析
        trend_state = self._analyze_trend_state()
        
        # 2. 波动性状态分析
        volatility_state = self._analyze_volatility_state()
        
        # 3. 成交量状态分析
        volume_state = self._analyze_volume_state()
        
        # 4. 价格动量分析
        momentum_state = self._analyze_momentum_state()
        
        # 5. 综合市场状态判断
        overall_state = self._determine_overall_state(
            trend_state, volatility_state, volume_state, momentum_state
        )
        
        return {
            'overall_state': overall_state,
            'trend_state': trend_state,
            'volatility_state': volatility_state,
            'volume_state': volume_state,
            'momentum_state': momentum_state,
            'dynamic_weights': self._get_dynamic_weights(overall_state)
        }
    
    def _analyze_trend_state(self) -> Dict:
        """分析趋势状态"""
        close_prices = self.data['Close']
        
        # 计算多个时间周期的移动平均线
        ma5 = close_prices.rolling(window=5).mean()
        ma10 = close_prices.rolling(window=10).mean()
        ma20 = close_prices.rolling(window=20).mean()
        ma50 = close_prices.rolling(window=50).mean()
        
        current_price = close_prices.iloc[-1]
        
        # 趋势强度评分
        trend_score = 0
        if current_price > ma5.iloc[-1]:
            trend_score += 1
        if current_price > ma10.iloc[-1]:
            trend_score += 1
        if current_price > ma20.iloc[-1]:
            trend_score += 1
        if current_price > ma50.iloc[-1]:
            trend_score += 1
        
        # 移动平均线排列
        ma_alignment_score = 0
        if ma5.iloc[-1] > ma10.iloc[-1]:
            ma_alignment_score += 1
        if ma10.iloc[-1] > ma20.iloc[-1]:
            ma_alignment_score += 1
        if ma20.iloc[-1] > ma50.iloc[-1]:
            ma_alignment_score += 1
        
        # 趋势斜率
        trend_slope = self._calculate_trend_slope(close_prices, 20)
        
        # 综合判断趋势状态
        if trend_score >= 3 and ma_alignment_score >= 2 and trend_slope > 0.001:
            trend_type = 'strong_uptrend'
        elif trend_score >= 2 and trend_slope > 0:
            trend_type = 'uptrend'
        elif trend_score <= 1 and ma_alignment_score <= 1 and trend_slope < -0.001:
            trend_type = 'strong_downtrend'
        elif trend_score <= 2 and trend_slope < 0:
            trend_type = 'downtrend'
        else:
            trend_type = 'sideways'
        
        return {
            'type': trend_type,
            'strength': (trend_score + ma_alignment_score) / 7 * 100,
            'slope': trend_slope,
            'ma_alignment': ma_alignment_score
        }
    
    def _analyze_volatility_state(self) -> Dict:
        """分析波动性状态"""
        close_prices = self.data['Close']
        
        # 计算不同周期的波动率
        returns = close_prices.pct_change().dropna()
        vol_5d = returns.rolling(window=5).std() * np.sqrt(252)
        vol_20d = returns.rolling(window=20).std() * np.sqrt(252)
        vol_60d = returns.rolling(window=60).std() * np.sqrt(252)
        
        current_vol_5d = vol_5d.iloc[-1] if not pd.isna(vol_5d.iloc[-1]) else 0
        current_vol_20d = vol_20d.iloc[-1] if not pd.isna(vol_20d.iloc[-1]) else 0
        current_vol_60d = vol_60d.iloc[-1] if not pd.isna(vol_60d.iloc[-1]) else 0
        
        # 波动率比较
        vol_ratio_short = current_vol_5d / current_vol_20d if current_vol_20d > 0 else 1
        vol_ratio_long = current_vol_20d / current_vol_60d if current_vol_60d > 0 else 1
        
        # 判断波动性状态
        if vol_ratio_short > 1.5 and vol_ratio_long > 1.3:
            vol_regime = 'high_volatility'
        elif vol_ratio_short < 0.7 and vol_ratio_long < 0.8:
            vol_regime = 'low_volatility'
        else:
            vol_regime = 'normal_volatility'
        
        return {
            'regime': vol_regime,
            'current_vol': current_vol_20d,
            'vol_ratio_short': vol_ratio_short,
            'vol_ratio_long': vol_ratio_long
        }
    
    def _analyze_volume_state(self) -> Dict:
        """分析成交量状态"""
        if 'Volume' not in self.data.columns:
            return {
                'state': 'unknown',
                'relative_volume': 1.0,
                'volume_trend': 'neutral'
            }
        
        volume = self.data['Volume']
        
        # 计算相对成交量
        avg_volume_20d = volume.rolling(window=20).mean()
        current_volume = volume.iloc[-1]
        relative_volume = current_volume / avg_volume_20d.iloc[-1] if avg_volume_20d.iloc[-1] > 0 else 1
        
        # 成交量趋势
        volume_trend_slope = self._calculate_trend_slope(volume, 10)
        
        if volume_trend_slope > 0.05:
            volume_trend = 'increasing'
        elif volume_trend_slope < -0.05:
            volume_trend = 'decreasing'
        else:
            volume_trend = 'stable'
        
        # 成交量状态
        if relative_volume > 1.5:
            volume_state = 'high_volume'
        elif relative_volume < 0.7:
            volume_state = 'low_volume'
        else:
            volume_state = 'normal_volume'
        
        return {
            'state': volume_state,
            'relative_volume': relative_volume,
            'volume_trend': volume_trend
        }
    
    def _analyze_momentum_state(self) -> Dict:
        """分析价格动量状态"""
        close_prices = self.data['Close']
        
        # 计算不同周期的动量
        momentum_5d = (close_prices.iloc[-1] / close_prices.iloc[-6] - 1) * 100 if len(close_prices) > 5 else 0
        momentum_10d = (close_prices.iloc[-1] / close_prices.iloc[-11] - 1) * 100 if len(close_prices) > 10 else 0
        momentum_20d = (close_prices.iloc[-1] / close_prices.iloc[-21] - 1) * 100 if len(close_prices) > 20 else 0
        
        # 动量强度评分
        momentum_score = 0
        if momentum_5d > 2:
            momentum_score += 1
        elif momentum_5d < -2:
            momentum_score -= 1
            
        if momentum_10d > 5:
            momentum_score += 1
        elif momentum_10d < -5:
            momentum_score -= 1
            
        if momentum_20d > 10:
            momentum_score += 1
        elif momentum_20d < -10:
            momentum_score -= 1
        
        # 动量状态判断
        if momentum_score >= 2:
            momentum_state = 'strong_positive'
        elif momentum_score == 1:
            momentum_state = 'positive'
        elif momentum_score == -1:
            momentum_state = 'negative'
        elif momentum_score <= -2:
            momentum_state = 'strong_negative'
        else:
            momentum_state = 'neutral'
        
        return {
            'state': momentum_state,
            'momentum_5d': momentum_5d,
            'momentum_10d': momentum_10d,
            'momentum_20d': momentum_20d,
            'score': momentum_score
        }
    
    def _determine_overall_state(self, trend_state, volatility_state, volume_state, momentum_state) -> str:
        """综合判断市场整体状态"""
        trend_type = trend_state['type']
        vol_regime = volatility_state['regime']
        momentum = momentum_state['state']
        
        # 强趋势市场
        if trend_type in ['strong_uptrend', 'strong_downtrend']:
            if vol_regime == 'low_volatility':
                return 'strong_trend_low_vol'
            elif vol_regime == 'high_volatility':
                return 'strong_trend_high_vol'
            else:
                return 'strong_trend'
        
        # 普通趋势市场
        elif trend_type in ['uptrend', 'downtrend']:
            if vol_regime == 'high_volatility':
                return 'trend_high_vol'
            else:
                return 'trend'
        
        # 震荡市场
        else:
            if vol_regime == 'high_volatility':
                return 'sideways_high_vol'
            elif vol_regime == 'low_volatility':
                return 'sideways_low_vol'
            else:
                return 'sideways'
    
    def _get_dynamic_weights(self, market_state: str) -> Dict:
        """
        根据市场状态返回动态权重
        
        Returns:
            包含各评分维度权重的字典
        """
        # 默认权重
        default_weights = {
            'position': 0.35,
            'resonance': 0.30,
            'volume': 0.20,
            'timeliness': 0.15
        }
        
        # 根据市场状态调整权重
        if market_state == 'strong_trend':
            # 强趋势市场：更重视位置和共振
            return {
                'position': 0.40,
                'resonance': 0.35,
                'volume': 0.15,
                'timeliness': 0.10
            }
        elif market_state == 'strong_trend_high_vol':
            # 强趋势高波动：更重视时效性和成交量
            return {
                'position': 0.30,
                'resonance': 0.25,
                'volume': 0.25,
                'timeliness': 0.20
            }
        elif market_state in ['sideways', 'sideways_low_vol']:
            # 震荡市场：更重视共振和成交量确认
            return {
                'position': 0.25,
                'resonance': 0.40,
                'volume': 0.25,
                'timeliness': 0.10
            }
        elif market_state == 'sideways_high_vol':
            # 高波动震荡：更重视时效性，降低其他权重
            return {
                'position': 0.25,
                'resonance': 0.30,
                'volume': 0.20,
                'timeliness': 0.25
            }
        elif market_state == 'trend_high_vol':
            # 趋势高波动：平衡各因素
            return {
                'position': 0.30,
                'resonance': 0.30,
                'volume': 0.20,
                'timeliness': 0.20
            }
        else:
            return default_weights
    
    def _calculate_trend_slope(self, data_series: pd.Series, window: int) -> float:
        """计算趋势斜率"""
        try:
            if len(data_series) < window:
                return 0
            
            recent_data = data_series.tail(window)
            x = np.arange(len(recent_data))
            y = recent_data.values
            
            # 使用最小二乘法计算斜率
            n = len(x)
            sum_x = np.sum(x)
            sum_y = np.sum(y)
            sum_xy = np.sum(x * y)
            sum_x2 = np.sum(x * x)
            
            slope = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x * sum_x)
            return slope / np.mean(y) if np.mean(y) != 0 else 0  # 标准化斜率
            
        except Exception:
            return 0